
interface Option {
  margin?: number,   // 周围边距
  position?: string
}

export default class Float {
  private rangeNodeX: Array<number> = []; // x方向可移动的最大值
  private rangeNodeY: Array<number> = []; // y方向可移动的最大值

  private floatNode: HTMLElement;  // 按钮节点

  private moveX: number = 0;  // * 当前在x方向上移动的距离
  private moveY: number = 0;  // * 当前在y方向上移动的距离

  private isMove: Boolean = false; // 移动状态
  private isClick: Boolean = false;  // 点击状态

  // 临时存储每次移动的 x/y 上的距离（鼠标松开后清零）
  private provisionalX: number = 0; 
  private provisionalY: number = 0; 

  // 存储按钮 dom 在页面上的宽高
  private floatNodeWidth: number = 0;
  private floatNodeHeight: number = 0;

  // ***** 初始化参数 *****
  private margin: number = 0; // 边距
  private initPosition: string = '';

  constructor(rangeNode: HTMLElement, floatNode: HTMLElement, options: Option = {}, clickCallback: Function) {
    
    this.floatNode = floatNode;
    this.margin = options.margin || 0;
    this.initPosition = options.position || ''

    let timeout: any;
    window.addEventListener('resize', () => {
      
      if (timeout) clearTimeout(timeout);
      timeout = setTimeout(() => {
        this.resize(rangeNode)
        this.initDom();
      }, 300)
    })
    
    this.resize(rangeNode);
    this.initDom();
    this.initBehavior(clickCallback);
  }

  // 计算可移动范围
  resize(node: HTMLElement) {
    let rangeNode = node.getBoundingClientRect();
    this.moveX = rangeNode.left;
    this.moveY = rangeNode.top;
    this.rangeNodeX = [this.moveX + this.margin, this.moveX + rangeNode.width - this.margin];
    this.rangeNodeY = [this.moveY + this.margin, this.moveY + rangeNode.height - this.margin];
  }

  // 初始化dom
  initDom() {
    this.floatNode.style.position = "absolute";

    this.floatNodeWidth = this.floatNode.getBoundingClientRect().width;
    this.floatNodeHeight = this.floatNode.getBoundingClientRect().width;


    
    if(this.initPosition === 'tl') {
      // 左上角
      this.moveX = this.rangeNodeX[0];
      this.moveY = this.rangeNodeY[0];
      this.floatNode.style.left = this.rangeNodeX[0] + "px";
      this.floatNode.style.top = this.rangeNodeY[0] + "px";
    } else if(this.initPosition === 'tr') {
      // 右上角    
      this.moveX = this.rangeNodeX[1] - this.floatNodeWidth;
      this.moveY = this.rangeNodeY[0];
      this.floatNode.style.left = this.rangeNodeX[1] - this.floatNodeWidth + "px";
      this.floatNode.style.top = this.rangeNodeY[0] + "px";
    } else if(this.initPosition === 'bl') {
      // 左下角
      this.moveX = this.rangeNodeX[0];
      this.moveY = this.rangeNodeY[1] - this.floatNodeHeight;
      this.floatNode.style.left = this.rangeNodeX[0] + "px";
      this.floatNode.style.top = this.rangeNodeY[1] - this.floatNodeHeight + "px";
    } else {
      // 右下角
      this.moveX = this.rangeNodeX[1] - this.floatNodeWidth;
      this.moveY = this.rangeNodeY[1] - this.floatNodeHeight;
      this.floatNode.style.left = this.rangeNodeX[1] - this.floatNodeWidth + "px";
      this.floatNode.style.top = this.rangeNodeY[1] - this.floatNodeHeight + "px";
    }
  }

  initBehavior(clickCallback: Function) {

    let startX = 0;
    let startY = 0;

    let marginLeft = 0;
    let marginTop = 0;


    this.floatNode.addEventListener('mousedown', (e) => {
      this.isMove = false;
      this.isClick = true;

      startX = e.clientX;
      startY = e.clientY;

      this.provisionalX = 0;
      this.provisionalY = 0;
    })

    document.addEventListener('mousemove', (e) => {
      if(!this.isClick) return
      this.isMove = true;
      setTimeout(() => {
        // 计算鼠标移动情况
        this.provisionalX = e.clientX - startX;
        this.provisionalY = e.clientY - startY;

        marginLeft = this.moveX + this.provisionalX;
        marginTop = this.moveY + this.provisionalY

        // 处理边界问题
        if (marginLeft > this.rangeNodeX[1] - this.floatNodeWidth) marginLeft = this.rangeNodeX[1] - this.floatNodeWidth;
        if (marginLeft < this.rangeNodeX[0]) marginLeft = this.rangeNodeX[0];
        if (marginTop > this.rangeNodeY[1] - this.floatNodeHeight) marginTop = this.rangeNodeY[1] - this.floatNodeHeight;
        if (marginTop < this.rangeNodeY[0]) marginTop = this.rangeNodeY[0];
        
        this.provisionalX = marginLeft - this.moveX;
        this.provisionalY = marginTop - this.moveY;

        this.floatNode.style.left = marginLeft + "px";
        this.floatNode.style.top = marginTop + "px";

          
      }, 0)

    })

    document.addEventListener('mouseup', () => {
      if (this.isMove && this.isClick) {
        this.isClick = false;
        this.isMove = false;
        setTimeout(() => {
          this.moveX += this.provisionalX;
          this.moveY += this.provisionalY;
          this.floatNode.style.left = this.moveX + "px";
          this.floatNode.style.top = this.moveY + "px";
        }, 0)
      } else if (this.isClick){
        this.isClick = false;
        this.isMove = false;
        clickCallback();
      }
    })

  }
}